﻿// Xshell Default Task Set Implementation
// 
// <copyright file="XsTaskSet.cs" company="TaskyMedia LLC">
//   Copyright © 2010 TaskyMedia LLC
// </copyright>

namespace Xshell
{
    using System;
    using System.Collections.Generic;
    using System.Xml;

    /// <summary>
    /// Contains a list of tasks and any conditions for task execution.
    /// </summary>
    internal class XsTaskSet : IXsTaskSet
    {
        /// <summary>
        /// Collection of <see cref="XsCondition" /> used to determine if the current Task Set should execute.
        /// </summary>
        private IEnumerable<XsCondition> _conditions;

        /// <summary>
        /// Collection of <see cref="XsTask" /> instances to execute.
        /// </summary>
        private IEnumerable<XsTask> _tasks;

        /// <summary>
        /// Initializes a new instance of the <see cref="XsTaskSet"/> class.
        /// </summary>
        /// <param name="conditions">The conditions for determining if the Task Set should execute.</param>
        /// <param name="tasks">The tasks to execute.</param>
        public XsTaskSet(IEnumerable<XsCondition> conditions, IEnumerable<XsTask> tasks)
        {
            this._conditions = conditions;
            this._tasks = tasks;
        }

        /// <summary>
        /// Gets a value indicating whether the task set conditions are valid.
        /// </summary>
        /// <value><c>true</c> if the task set conditions are valid; otherwise, <c>false</c>.</value>
        public bool AreConditionsValid
        {
            get
            {
                if (this._conditions == null)
                {
                    return true;
                }

                if (!this._conditions.GetEnumerator().MoveNext())
                {
                    return true;
                }

                foreach (XsCondition condition in this._conditions)
                {
                    if (!condition.IsValid)
                    {
                        return false;
                    }
                }

                return true;
            }
        }

        /// <summary>
        /// Creates a new instance of the <see cref="XsTaskSet"/> class based on the input Xml.
        /// </summary>
        /// <param name="xr">The <see cref="System.Xml.XmlReader"/> instance containing the TaskSet Xml.</param>
        /// <param name="metadataCache">The metadata cache.</param>
        /// <returns>
        /// A new instance of the <see cref="XsTaskSet"/> class
        /// </returns>
        /// <remarks>The calling method should *not* call ReadStartElement() before invoking this method.</remarks>
        public static XsTaskSet CreateFromXml(XmlReader xr, IMetadataCache metadataCache)
        {
            List<XsCondition> conditions = new List<XsCondition>();
            List<XsTask> tasks = new List<XsTask>();

            // Read any attributes for the TaskSet -- right now this is how Conditions are defined
            if (xr.AttributeCount > 0)
            {
                xr.MoveToFirstAttribute();

                for (int i = 0; i < xr.AttributeCount; i++)
                {
                    XsCondition condition = XsCondition.CreateFromString(metadataCache, xr.Name, xr.Value);
                    conditions.Add(condition);
                    xr.MoveToNextAttribute();
                }
            }

            // Read all tasks in the TaskSet
            bool isEmptySet = xr.IsEmptyElement;
            xr.ReadStartElement();
            if (!isEmptySet)
            {
                while (xr.IsStartElement())
                {
                    string taskName = xr.Name;
                    List<XsArgument> commandArgs = new List<XsArgument>();
                    bool isEmptyTask = xr.IsEmptyElement;

                    // Read the Task element and any command arguments
                    xr.ReadStartElement();
                    if (!isEmptyTask)
                    {
                        // Build a list of command arguments
                        while (xr.IsStartElement())
                        {
                            string argumentName = xr.Name;
                            string argumentValue = xr.ReadElementContentAsString();
                            commandArgs.Add(new XsArgument(argumentName, argumentValue));
                        }

                        // Only read the end element if the element was not empty
                        xr.ReadEndElement();
                    }

                    tasks.Add(XsTask.CreateFromString(metadataCache, taskName, commandArgs.ToArray()));
                }

                // Only read the end element if the element was not empty
                xr.ReadEndElement();
            }

            return new XsTaskSet(conditions, tasks);
        }

        /// <summary>
        /// Executes the tasks in the current <see cref="XsTaskSet"/> instance.
        /// </summary>
        public void Execute()
        {
            if (this._tasks != null)
            {
                foreach (XsTask task in this._tasks)
                {
                    task.Execute();
                }
            }
        }
    }
}
